import random
import re
from datetime import datetime

from flask import current_app, jsonify
from flask import request, make_response
from flask import session
from info import constants, redis_store, db
from info.libs.yuntongxun.sms import CCP
from info.models import User
from info.modules.passport import passport_blu
from info.utils.captcha.captcha import captcha
from info.utils.response_code import RET


# 退出路由(删除session)
@passport_blu.route('/logout', methods=['POST'])
def logout():
    session.pop('user_id', None)
    session.pop('nick_name', None)
    session.pop('mobile', None)
    return jsonify(errno=RET.OK, errmsg='退出成功')


# 登陆接口
@passport_blu.route('/login', methods=['POST'])
def login():
    # 获取参数并判断是否有数据
    json_dict = request.json
    mobile = json_dict.get('mobile')
    password = json_dict.get('password')

    # 判断是否有数据
    if not all([mobile, password]):
        # 用jsonify的格式实现前后端数据交互
        return jsonify(errno=RET.NODATA, errmsg='参数不全')

    if not re.match(r'1[3-9][0-9]{9}$', mobile):
        return jsonify(errno=RET.ROLEERR, errmsg='手机号码错误')

    # 从数据库查询出指定用户
    try:
        user = User.query.filter_by(mobile=mobile).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DATAERR, errmsg='查询数据库错误')

    # 判断用户名和密码是否正确是否存在
    if (not user) or (not user.check_passowrd(password)):
        return jsonify(errno=RET.USERERR, errmsg='用户名或密码错误')
        # 到这一步说明 所有的否匹配上了 保存用户登陆状态(就是设置sesesion)

    session['user_id'] = user.id
    session['user_name'] = user.mobile
    session['user_mobile'] = user.mobile

    # 设置一个最后登录时间
    user.last_login = datetime.now()

    # 登陆成功
    return jsonify(errno=RET.OK, errmsg='登陆成功')


# 注册接口
@passport_blu.route('/register', methods=['POST'])
def register():
    # 从浏览器的请求中获取参数(手机号, 短信验证码, 密码)
    params_dict = request.json
    mobile = params_dict.get('mobile')
    sms_code = params_dict.get('sms_code')
    password = params_dict.get('password')

    # 校验参数(完整性,手机号格式)
    if not all([mobile, sms_code, password]):
        return jsonify(errno=RET.PARAMERR, errmsg='参数有误')

    if not re.match(r'1[3456789][0-9]{9}', mobile):
        return jsonify(errno=RET.DATAERR, errmsg='手机号码不对')
    # 从redis获取短信验证码 判断是否过期
    try:
        real_sms_code = redis_store.get('sms_' + mobile)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DATAERR, errmsg='数据库查询出错')
    if not real_sms_code:
        return jsonify(errno=RET.DBERR, errmsg='验证码过期')
    if real_sms_code != sms_code:
        return jsonify(errno=RET.PARAMERR, errmsg='验证码输入错误')
    # 对比成功后 验证码为了安全或者逻辑完善,最好是删除验证码
    try:
        redis_store.delete('sms_' + mobile)
    except Exception as e:
        current_app.looger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='数据库查询错误')

    # 对比成功,判断手机号是否已被注册, 创建User模型,添加到数据库中
    try:
        # 从数据库中查找手机号
        user = User.query.filter_by(mobile=mobile).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='数据库查询失败')
    if user:
        return jsonify(errno=RET.DATAEXIST, errmsg='手机号已注册')
    # 创建user实例对象
    user = User()
    # 添加数据到数据库
    user.nick_name = mobile
    # 密码已加密
    # 调用了模板里的方法直接就可以给密码加密,
    user.password = password
    user.mobile = mobile

    try:
        # 提交数据
        db.session.add(user)
        db.session.commit()
    except Exception as e:
        # 数据库操作失败需要回滚
        db.session.rollback()
        current_app.logger.error(e)
        return jsonify(errni=RET.DBERR, errmsg='数据库查询失败')

    # 实现登陆就是设置session
    session['user_id'] = user.id
    session['user_name'] = user.mobile
    session['user_mobile'] = user.mobile
    # 登陆成功
    return jsonify(errno=RET.OK, errmsg='登陆成功')


# 短信验证码接口
@passport_blu.route('/sms_code', methods=['POST'])
def get_sms_code():
    # 获取浏览器携带的参数(手机号码,图像验证码内容,图像验证码ID)
    # request.data接收的是json格式的字符串
    params_dict = request.json
    mobile = params_dict.get('mobile')
    image_code = params_dict.get('image_code')
    image_code_id = params_dict.get('image_code_id')
    # 效验数据(1.数据的完整性,2.正则匹配手机号码)
    if not all([mobile, image_code, image_code_id]):
        return jsonify(errno=RET.PARAMERR, errmsr='参数不全')
    if not re.match(r'1[3456789][0-9]{9}$', mobile):
        return jsonify(errno=RET.PARAMERR, errmsg='手机号不对')

    # 逻辑处理
    try:
        real_image_code = redis_store.get('image_code_id' + image_code_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='数据库查询失败')

    # 判断验证码是否过期
    if not real_image_code:
        return jsonify(errno=RET.NODATA, errmsg='验证码过期')

    # 安全起见,需要删除验证码
    try:
        redis_store.delete('image_code_id' + image_code_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.NODATA,errmsg='数据库删除失败')

    # 从数据库对比验证码是否一致
    if real_image_code.upper() != image_code.upper():
        return jsonify(errno=RET.DATAERR, errmsg='验证码输入错误')

    # 判断手机号码书否被注册过
    try:
        # 从数据库中查找手机号
        user = User.query.filter_by(mobile=mobile).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='数据库查询失败')
    if user:
        return jsonify(errno=RET.DATAEXIST, errmsg='手机号已注册')

    # 如果对比一致,生成验证码的值(第三方负责发送短信),保存到redis数据库中
    sms_code_str = '%06d' % random.randint(0, 9999)
    current_app.logger.error('sms_code:%s' % sms_code_str)
    print(sms_code_str)

    # 调用第三方发送短息
    # num = CCP().send_template_sms(mobile,[sms_code_str,constants.SMS_CODE_REDIS_EXPIRES],1)

    # 判断短信是否发送成功
    # if num != 0:
    #     return jsonify(errno=RET.THIRDERR,errmsg='短信发送失败')

    # 操作数据库时最好try一下
    try:
        redis_store.set('sms_' + mobile, sms_code_str, constants.SMS_CODE_REDIS_EXPIRES)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='数据库错误')

    # 返回收到验证码成功的数据
    return jsonify(errno=RET.OK, errmsg='发送成功')


# 图片验证码接口
@passport_blu.route('/image_code')
def get_image_code():
    # 1. 获取参数id
    image_code_id = request.args.get('image_code_id')

    # 2. 生成验证码内容
    name, text, image_data = captcha.generate_captcha()
    print(text)
    # 3. 保存到redis数据库中, 参数3是导入常量值,设置图片过期时间
    try:
        redis_store.set('image_code_id' + image_code_id, text, constants.IMAGE_CODE_REDIS_EXPIRES)
    except Exception as e:
        # 记录错误信息
        current_app.logger.errer(e)
        # 返回json数据  前后端的数据采用json格式返回
        return jsonify(erron=RET.DBERR, errmgs='图片保存失败')
    # 4. 返回图像
    # 修改请求头的格式
    response = make_response(image_data)
    response.headers['Content-type'] = 'image/jpg'
    return response
